<html>
<head>
  <script src="../OLLoader.js"></script>
  <script type="text/javascript">
    // turn off animation frame handling, so we can check img urls in tests
    delete OpenLayers.Layer.Grid.prototype.queueTileDraw;

    var isMozilla = (navigator.userAgent.indexOf("compatible") == -1);
    var tile; 
    
    var map, layer;
    function setUp() {
        map = new OpenLayers.Map("map");
        layer = new OpenLayers.Layer(null, {
            isBaseLayer: true
        });
        map.addLayer(layer)
        map.setCenter(new OpenLayers.LonLat(0, 0));
    }
    
    function tearDown() {
        map.destroy();
        map = null;
        layer = null;
    }

    function test_Tile_Image_constructor (t) {
        t.plan( 6 );
        
        setUp();
        
        var position = new OpenLayers.Pixel(20,30);
        var bounds = new OpenLayers.Bounds(1,2,3,4);
        var url = "http://www.openlayers.org/dev/tests/tileimage";
        var size = new OpenLayers.Size(5,6);
        tile = new OpenLayers.Tile.Image(layer, position, bounds, url, size);
        
        t.ok( tile instanceof OpenLayers.Tile.Image, "new OpenLayers.Tile returns Tile object" );
        t.ok( tile.layer == layer, "tile.layer is set correctly");
        t.ok( tile.position.equals(position), "tile.position is set correctly");
        t.ok( tile.bounds.equals(bounds), "tile.bounds is set correctly");
        t.eq( tile.url, url, "tile.url is set correctly");
        t.ok( tile.size.equals(size), "tile.size is set correctly");
        
        tearDown();
    }

    function test_destroy_observers(t) {
        t.plan(2);

        var map = new OpenLayers.Map('map');
        var layer = new OpenLayers.Layer.WMS( "OpenLayers WMS", 
            "../../img/blank.gif", {layers: 'basic'}); 
        map.addLayer(layer);

        var position = new OpenLayers.Pixel(20,30);
        var bounds = new OpenLayers.Bounds(1,2,3,4);
        var size = new OpenLayers.Size(5,6);

        // with alpha hack
        var withAlpha = new OpenLayers.Tile.Image(layer, position, bounds, null, size);
        withAlpha.layerAlphaHack = true;

        withAlpha.draw();
        var cacheID = withAlpha.imgDiv._eventCacheID;
        withAlpha.destroy();
        
        t.eq(OpenLayers.Event.observers[cacheID], undefined, 
             "With alpha hack: imgDiv observers are cleared in destroy");

        // without alpha hack
        var withoutAlpha = new OpenLayers.Tile.Image(layer, position, bounds, null, size);
        withoutAlpha.layerAlphaHack = false;

        withoutAlpha.draw();
        var cacheID = withoutAlpha.imgDiv._eventCacheID;
        withoutAlpha.destroy();

        t.eq(OpenLayers.Event.observers[cacheID], undefined, 
             "Without alpha hack: imgDiv observers are cleared in destroy");

        map.destroy();
    }

    function test_Tile_Image_async (t) {
        t.plan( 3 );
        var map   = new OpenLayers.Map('map');
        var layer = new OpenLayers.Layer.WMS(
            "Name",
            "../../img/blank.gif",
            {layers: 'basic'}, {async: true, getURLasync: function(bounds, callback, scope) {
                callback.call(scope, this.getURL(bounds));
            }}
        ); 
        map.addLayer(layer);

        var position = new OpenLayers.Pixel(20,30);
        var bounds = new OpenLayers.Bounds(1,2,3,4);
        tile = layer.addTile(bounds, position);
        tile.renderTile();
        t.delay_call(0.1, function() {
            var expected = new Image();
            expected.src = layer.getURL(bounds);
            t.eq(tile.imgDiv.src, expected.src, "image src correct for async request");
            t.eq(tile.asyncRequestId, 1, "asyncRequestId correct after renderTile");
            tile.renderTile();
        });
        t.delay_call(0.2, function() {
            t.eq(tile.asyncRequestId, 2, "asyncRequestId correct after subsequent renderTile");
            tile.destroy();
            layer.destroy();
            map.destroy();
        });
    }

    function test_Tile_Image_draw (t) {
        t.plan(8);

        var map = new OpenLayers.Map('map');
        
        var size = new OpenLayers.Size(5,6);
        layer = new OpenLayers.Layer.WMS("Name",
                                         "../../img/blank.gif",
                                         null,
                                         {tileSize: size});  
        map.addLayer(layer);  
        var position = new OpenLayers.Pixel(20,30);
        var bounds = new OpenLayers.Bounds(1,2,3,4);
        var url = "http://www.openlayers.org/dev/tests/tileimage";
        tile = new OpenLayers.Tile.Image(layer, position, bounds, url, size);
        
        tile.events.register("loadstart", this, function() { 
            t.ok(true, "loadstart triggered");
        });
        tile.events.register("reload", this, function() { 
            t.ok(true, "reload triggered");
        });
                
        //this should trigger a "loadstart" event
        tile.draw();
        
        var img = tile.imgDiv;
        
        if (!isMozilla)
            t.ok( true, "skipping element test outside of Mozilla");
        else
            t.ok( tile.imgDiv instanceof HTMLElement, "tile.draw creates an image");
        if (!isMozilla)
            t.ok( true, "skipping element test outside of Mozilla");
        else
            t.ok( img instanceof HTMLImageElement, "tile.draw creates an image");
        var tParams = {
            SERVICE: "WMS", VERSION: "1.1.1",
            REQUEST: "GetMap", STYLES: "",
            FORMAT: "image/jpeg",
            SRS: "EPSG:4326", BBOX: [1,2,3,4],
            WIDTH: String(size.w), HEIGHT: String(size.h)
        };
        var expected = new Image();
        expected.src =  "../../img/blank.gif?" + OpenLayers.Util.getParameterString(tParams)
        t.delay_call(0.1, function() {
            t.eq( img.src, expected.src, "tile.draw creates an image");
        });
        t.eq( tile.imgDiv.style.width, "5%", "Image width is correct" );
        t.eq( tile.imgDiv.style.height, "6%", "Image height is correct" );
        t.ok( tile.imgDiv.parentNode === layer.div, "Image is directly appended to the layer div" ); 

        // this should trigger a "reload" event (since the image never actually
        // loads in tests)
        tile.draw();
        
    }
    function test_Tile_Image_OutsideMaxExtent(t) {
        t.plan( 11 );
        var position = new OpenLayers.Pixel(20,30);
        var bounds = new OpenLayers.Bounds(1,2,3,4);
        var url = "http://www.openlayers.org/dev/tests/tileimage";
        var size = new OpenLayers.Size(5,6);
        var map = new OpenLayers.Map('map');
        var layer = new OpenLayers.Layer.WMS( "OpenLayers WMS", 
            "../../img/blank.gif", {layers: 'basic'}, {reproject:false, encodeBBOX: true}); 
        map.addLayer(layer);
        tile = new OpenLayers.Tile.Image(layer, position, new OpenLayers.Bounds(-185,-90,-180,90), url, size);
        tile.draw()
        t.eq(tile.imgDiv, null, "Images against side of maxextent don't load");
        tile = new OpenLayers.Tile.Image(layer, position, new OpenLayers.Bounds(-181,-91,180,90), url, size);
        tile.draw()
        var tParams = {
            LAYERS: "basic", SERVICE: "WMS", VERSION: "1.1.1",
            REQUEST: "GetMap", STYLES: "",
            FORMAT: "image/jpeg",
            SRS: "EPSG:4326", BBOX: "-181,-91,180,90",
            WIDTH: "256", HEIGHT: "256"
        };
        t.eq(tile.url,
             "../../img/blank.gif?" + OpenLayers.Util.getParameterString(tParams),
             "Images over edges of maxextent do load");
        tile = new OpenLayers.Tile.Image(layer, position, new OpenLayers.Bounds(-181,-90,180,90), url, size);
        tile.draw()
        tParams = OpenLayers.Util.extend(tParams, {BBOX: "-181,-90,180,90"});
        t.eq(tile.url,
             "../../img/blank.gif?" + OpenLayers.Util.getParameterString(tParams),
             "Images over edges of maxextent do load");
        tile = new OpenLayers.Tile.Image(layer, position, new OpenLayers.Bounds(-180,-90,180,90), url, size);
        tile.draw()
        tParams = OpenLayers.Util.extend(tParams, {BBOX: "-180,-90,180,90"});
        t.eq(tile.url,
             "../../img/blank.gif?" + OpenLayers.Util.getParameterString(tParams),
             "Image covering all of extent loads");
        tile = new OpenLayers.Tile.Image(layer, position, new OpenLayers.Bounds(-80,-45,80,45), url, size);
        tile.draw()
        tParams = OpenLayers.Util.extend(tParams, {BBOX: "-80,-45,80,45"});
        t.eq(tile.url,
             "../../img/blank.gif?" + OpenLayers.Util.getParameterString(tParams),
             "Image covering small part of extent loads");
        tile = new OpenLayers.Tile.Image(layer, position, new OpenLayers.Bounds(-185,-95,185,95), url, size);
        tile.draw()
        tParams = OpenLayers.Util.extend(tParams, {BBOX: "-185,-95,185,95"});
        t.eq(tile.url,
             "../../img/blank.gif?" + OpenLayers.Util.getParameterString(tParams),
             "Image covering more than all of extent loads");

        layer.displayOutsideMaxExtent=1;
        tile = new OpenLayers.Tile.Image(layer, position, new OpenLayers.Bounds(-185,-90,-180,90), url, size);
        tile.draw()
        tParams = OpenLayers.Util.extend(tParams, {BBOX: "-185,-90,-180,90"});
        t.eq(tile.url,
             "../../img/blank.gif?" + OpenLayers.Util.getParameterString(tParams),
             "Images against side of maxextent do load with displayOutsideMaxExtent");
        tile = new OpenLayers.Tile.Image(layer, position, new OpenLayers.Bounds(-181,-90,180,90), url, size);
        tile.draw()
        tParams = OpenLayers.Util.extend(tParams, {BBOX: "-181,-90,180,90"});
        t.eq(tile.url,
             "../../img/blank.gif?" + OpenLayers.Util.getParameterString(tParams),
             "Images over edges of maxextent do load with displayOutsideMaxExtent set");
        tile = new OpenLayers.Tile.Image(layer, position, new OpenLayers.Bounds(-180,-90,180,90), url, size);
        tile.draw()
        tParams = OpenLayers.Util.extend(tParams, {BBOX: "-180,-90,180,90"});
        t.eq(tile.url,
             "../../img/blank.gif?" + OpenLayers.Util.getParameterString(tParams),
             "Image covering all of extent loads with display outside max extent");
        tile = new OpenLayers.Tile.Image(layer, position, new OpenLayers.Bounds(-80,-45,80,45), url, size);
        tile.draw()
        tParams = OpenLayers.Util.extend(tParams, {BBOX: "-80,-45,80,45"});
        t.eq(tile.url,
             "../../img/blank.gif?" + OpenLayers.Util.getParameterString(tParams),
             "Image covering small part of extent loads with display outside max extent");
        tile = new OpenLayers.Tile.Image(layer, position, new OpenLayers.Bounds(-185,-95,185,95), url, size);
        tile.draw()
        tParams = OpenLayers.Util.extend(tParams, {BBOX: "-185,-95,185,95"});
        t.eq(tile.url,
             "../../img/blank.gif?" + OpenLayers.Util.getParameterString(tParams),
             "Image covering more than all of extent loads");
    } 
    function test_Tile_Image_Display_After_Move(t) {
        t.plan(2);
        var position = new OpenLayers.Pixel(20,30);
        var bounds = new OpenLayers.Bounds(1,2,3,4);
        var url = "http://www.openlayers.org/dev/tests/tileimage";
        var size = new OpenLayers.Size(5,6);
        var map = new OpenLayers.Map('map');
        var layer = new OpenLayers.Layer.WMS( "OpenLayers WMS", 
            "../../img/blank.gif", {layers: 'basic'}); 
        map.addLayer(layer);
        map.zoomToMaxExtent();
        tile = new OpenLayers.Tile.Image(layer, position, new OpenLayers.Bounds(-90,-85,-90,85), url, size);
        tile.draw();
        tile.moveTo(new OpenLayers.Bounds(-185,-90,-180,-80), new OpenLayers.Pixel(-180,-85), true);
        t.delay_call( 1, function() { t.eq(tile.imgDiv.style.visibility, "hidden", "Tile image is invisible.") } );
        var layer = new OpenLayers.Layer.WMS( "OpenLayers WMS", 
            "../../img/blank.gif", {layers: 'basic'}, {'alpha':true});
        map.addLayer(layer);
        tile = new OpenLayers.Tile.Image(layer, position, new OpenLayers.Bounds(-90,-85,-90,85), url, size);
        tile.draw();
        tile.moveTo(new OpenLayers.Bounds(-185,-90,-180,-80), new OpenLayers.Pixel(-180,-85), true)
        t.delay_call( 1, function() { t.eq(tile.imgDiv.style.visibility, "hidden", "Alpha tile image is invisible.") } );
        
    }

    function test_Tile_Image_gutters(t) {
        t.plan(5);
        
        var gutter = 0;
        var name = 'Test Layer';
        var url = "http://octo.metacarta.com/cgi-bin/mapserv";
        var params = { map: '/mapdata/vmap_wms.map', 
                       layers: 'basic', 
                       format: 'image/png'};


        var map = new OpenLayers.Map('map');
        var layer = new OpenLayers.Layer.WMS(name, url, params, {gutter: gutter});
        map.addLayer(layer);
        map.setCenter(new OpenLayers.LonLat(0,0), 5);
        
        var tile = layer.grid[0][0];
        t.ok(tile.layer.imageSize == null,
             "zero size gutter doesn't set image size"); 

        var zero_gutter_bounds = tile.bounds;
        
        map.destroy();
        
        var gutter = 15;
        var map = new OpenLayers.Map('map');
        var layer = new OpenLayers.Layer.WMS(name, url, params, {gutter: gutter});
        map.addLayer(layer);
        map.setCenter(new OpenLayers.LonLat(0,0), 5);
        var tile = layer.grid[0][0];
        t.ok(tile.layer.imageSize.equals(new OpenLayers.Size(tile.size.w + (2 * gutter),
                                                             tile.size.h + (2 * gutter))),
             "gutter properly changes image size"); 

        var offsetLeft = -(gutter / layer.tileSize.w * 100) | 0;
        var offsetTop = -(gutter / layer.tileSize.h * 100) | 0;
        t.eq(parseInt(tile.imgDiv.style.left, 10), offsetLeft,
             "gutter properly sets image left style");
        t.eq(parseInt(tile.imgDiv.style.top, 10), offsetTop,
             "gutter properly sets image top style");
        t.ok(tile.bounds.equals(zero_gutter_bounds),
             "gutter doesn't affect tile bounds");

        map.destroy();
    }
    
    function test_createBackBuffer(t) {
        t.plan(3);

        var map = new OpenLayers.Map('map');
        var layer = new OpenLayers.Layer.WMS( "OpenLayers WMS", 
            "../../img/blank.gif", {layers: 'basic'});
        map.addLayer(layer);
        map.setCenter(new OpenLayers.LonLat(0,0), 5);
        var tile = layer.grid[0][0];

        // we're going to create a back buffer while the image
        // is actually loading, so we call stopObservingElement
        // to avoid any unexpected behavior
        tile.isLoading = false;
        OpenLayers.Event.stopObservingElement(tile.imgDiv);

        var img = tile.imgDiv;
        var left = img.style.left;
        var bb = tile.createBackBuffer();
        t.eq(bb.style.left, left, "backbuffer has same left style as frame");
        t.ok(bb === img, "image appended to bb");
        t.ok(tile.imgDiv == null, "image reference removed from tile");
        map.destroy();
    }

    function test_onImageLoad(t) {
        t.plan(3);

        var map = new OpenLayers.Map('map');
        var layer = new OpenLayers.Layer.WMS( "OpenLayers WMS",
            "../../img/blank.gif", {layers: 'basic'}, {opacity: 0.5});
        map.addLayer(layer);
        map.setCenter(new OpenLayers.LonLat(0,0), 5);

        var tile = layer.grid[0][0];

        var log;
        tile.events.on({loadend: function() { log++; }});

        log = 0;
        tile.onImageLoad();
        t.eq(tile.imgDiv.style.visibility, 'inherit',
             'onImageLoad makes the image visible');
        t.eq(parseFloat(tile.imgDiv.style.opacity), 0.5,
             'onImageLoad sets the expected opacity for the image');
        t.eq(log, 1,
             'onImageLoad does trigger loadend');

        map.destroy();
    }

    function test_getCanvasContext(t) {
        if (!OpenLayers.CANVAS_SUPPORTED) {
            t.plan(0);
        } else {
            t.plan(1);

            var map = new OpenLayers.Map('map');
            var layer = new OpenLayers.Layer.WMS("blank",
                "../../img/blank.gif", {layers: 'fake'});
            map.addLayer(layer);
            map.setCenter(new OpenLayers.LonLat(0, 0), 5);

            t.delay_call(5, function() {
                var tile = layer.grid[0][0];
                if (tile.isLoading) {
                    t.ok(false, "test_getCanvasContext timeout");
                } else {
                    t.ok(tile.getCanvasContext() instanceof CanvasRenderingContext2D,
                         "getCanvasContext() returns CanvasRenderingContext2D instance");
                }
                map.destroy();
            });
        }
    }

    /*
     * A series of tests to verify the dimensions and positions
     * of the tile frame and img after draw.

     * Written for https://github.com/openlayers/openlayers/issues/441
     */
    function test_draw_without_gutter_without_frame(t) {
        t.plan(5);

        var map = new OpenLayers.Map('map');
        var layer = new OpenLayers.Layer.WMS('blank',
                        '../../img/blank.gif',
                        {layers: 'fake'},
                        {isBaseLayer: true});
        map.addLayer(layer);
        var tile = new OpenLayers.Tile.Image(
                            layer,
                            new OpenLayers.Pixel(6, 6),
                            new OpenLayers.Bounds(5, 45, 6, 46),
                            null,
                            new OpenLayers.Size(256, 256));

        tile.draw();
        t.eq(tile.frame, null, 'no frame');
        t.eq(parseInt(tile.imgDiv.style.left, 10), 6, 'correct tile img left');
        t.eq(parseInt(tile.imgDiv.style.top, 10), 6, 'correct tile img top');
        t.eq(parseInt(tile.imgDiv.style.width, 10), 256, 'correct tile img width');
        t.eq(parseInt(tile.imgDiv.style.height, 10), 256, 'correct tile img height');

        map.destroy();
    }
    function test_draw_without_gutter_with_frame(t) {
        t.plan(8);

        var map = new OpenLayers.Map('map');
        var layer = new OpenLayers.Layer.WMS('blank',
                        '../../img/blank.gif',
                        {layers: 'fake'},
                        {isBaseLayer: true});
        map.addLayer(layer);
        layer.gutter = 1; // this is just for a frame to be created for
                          // the tile
        var tile = new OpenLayers.Tile.Image(
                            layer,
                            new OpenLayers.Pixel(6, 6),
                            new OpenLayers.Bounds(5, 45, 6, 46),
                            null,
                            new OpenLayers.Size(256, 256));
        layer.gutter = null;

        tile.draw();
        t.eq(parseInt(tile.frame.style.left, 10), 6, 'correct tile frame left');
        t.eq(parseInt(tile.frame.style.top, 10), 6, 'correct tile frame top');
        t.eq(parseInt(tile.frame.style.width, 10), 256, 'correct tile frame width');
        t.eq(parseInt(tile.frame.style.height, 10), 256, 'correct tile frame height');
        t.eq(parseInt(tile.imgDiv.style.left, 10), 0, 'correct tile img left');
        t.eq(parseInt(tile.imgDiv.style.top, 10), 0, 'correct tile img top');
        t.eq(parseInt(tile.imgDiv.style.width, 10), 100, 'correct tile img width');
        t.eq(parseInt(tile.imgDiv.style.height, 10), 100, 'correct tile img height');

        map.destroy();
    }
    function test_draw_with_gutter(t) {
        t.plan(8);

        var map = new OpenLayers.Map('map');
        var layer = new OpenLayers.Layer.WMS('blank',
                        '../../img/blank.gif',
                        {layers: 'fake'},
                        {isBaseLayer: true, gutter: 15});
        map.addLayer(layer);
        var tile = new OpenLayers.Tile.Image(
                            layer,
                            new OpenLayers.Pixel(6, 6),
                            new OpenLayers.Bounds(5, 45, 6, 46),
                            null,
                            new OpenLayers.Size(256, 256));

        tile.draw();
        t.eq(parseInt(tile.frame.style.left, 10), 6, 'correct tile frame left');
        t.eq(parseInt(tile.frame.style.top, 10), 6, 'correct tile frame top');
        t.eq(parseInt(tile.frame.style.width, 10), 256, 'correct tile frame width');
        t.eq(parseInt(tile.frame.style.height, 10), 256, 'correct tile frame height');
        t.eq(parseInt(tile.imgDiv.style.left, 10), -5, 'correct tile img left');
        t.eq(parseInt(tile.imgDiv.style.top, 10), -5, 'correct tile img top');
        t.eq(parseInt(tile.imgDiv.style.width, 10), 111, 'correct tile img width');
        t.eq(parseInt(tile.imgDiv.style.height, 10), 111, 'correct tile img height');

        map.destroy();
    }

  </script>
</head>
<body>
<div id="map" style="height:550px;width:500px"></div>
</body>
</html>

